package sparkml_study

import org.apache.spark.sql.SparkSession
import org.apache.spark.ml.stat.Correlation
import org.apache.spark.ml.linalg.{Matrix,Vectors,Vector}
import org.apache.spark.sql.Row

object Correlation_XiangGuanXing {
  def main(args: Array[String]): Unit = {
    /*
        相关性在机器学习中的应用
    1.特征选择：
    在机器学习中，理解不同特征之间的相关性非常重要。高度相关的特征（例如两列数据几乎完全一致）可能导致多重共线性问题，
    从而影响模型的性能，尤其是在回归模型中。通过计算相关性，可以发现和删除冗余特征，简化模型，减少计算负担，避免过拟合。

    高相关性特征：如果两个特征之间的相关性较高，通常可以删除其中一个特征，或将其合并成一个特征。
    低相关性特征：这些特征之间的信息量少，可能不对模型的预测有重要贡献。
    2.特征工程：
    在某些情况下，相关性还可以用来创造新的特征。例如，如果你发现某两个特征之间具有较强的相关性，可以考虑将它们合并为一个新的特征（如求和、求差等），或者进行主成分分析（PCA）来降低维度。

    3.目标变量与特征之间的相关性：
    通过检查目标变量与各个特征之间的相关性，可以帮助理解哪些特征对预测结果有更大的影响。例如，在回归任务中，特征与目标变量之间的高相关性通常意味着该特征可能在模型中起着重要作用。

    4.模型解释：
    了解不同特征之间的相关性有助于解释机器学习模型的行为。某些模型（例如线性回归、逻辑回归）直接依赖于特征之间的相关性来构建预测方程。因此，通过分析相关性，研究人员可以更好地理解模型的决策过程，尤其是在模型是“可解释的”时。
     */




    val spark=SparkSession.builder()
      .master("local[*]")
      .appName("Correlation(相关性)")
      .getOrCreate()

    //  导入隐式转换避免多余的报错
    import spark.implicits._

    //  创建实验数据
    //  Vectors.sparse(4, Seq((0, 2.0), (2, -1.0)))，它表示一个 4 维的稀疏向量，其中第 0 维和第 2 维的值分别
    //  为 2.0 和 -1.0。
    val data: Seq[Vector] = Seq(
      Vectors.sparse(4, Seq((0, 2.0), (2, -1.0))), //  稀疏向量
      Vectors.dense(3.0, 0.0, 4.0, 5.0), //  稠密向量
      Vectors.dense(6.0, 8.0, 0.0, 7.0)
    )

    //  将实验数据转化为DataFrame
    /*
        2. map(Tuple1.apply) 的作用
    map 函数是 Scala 中用于转换集合的高阶函数，它会对集合中的每个元素应用一个函数，并返回一个新的集合。
    Tuple1.apply 是一个将一个元素包装成 Tuple1 的函数。Tuple1 是一个包含单个元素的元组类，意味着 map(Tuple1.apply) 会将每个 Vector 包装成一个 Tuple1[Vector]。例如：
    Vectors.sparse(4, Seq((0, 2.0), (2, -1.0))) 会变成 Tuple1(Vectors.sparse(4, Seq((0, 2.0), (2, -1.0))))
    Vectors.dense(3.0, 0.0, 4.0, 5.0) 会变成 Tuple1(Vectors.dense(3.0, 0.0, 4.0, 5.0))
    最终，data.map(Tuple1.apply) 会将 data 中的每个 Vector 转换为一个 Tuple1[Vector]，返回一个新的集合，这个新的集合的类型是 Seq[Tuple1[Vector]]。

    3. 为什么需要 Tuple1.apply
    在 Spark 中，DataFrame 是基于 Row 类型的集合来构建的。如果你想将一个 Seq[Vector] 转换成 DataFrame，你需要将每个元素包装成一个符合 Row 类型的结构。Tuple1 是 Spark 中的一种常见封装类型，表示一个只有一个元素的元组。在这里，Tuple1.apply 用于将每个 Vector 包装成 Tuple1，从而可以被正确地转换为 DataFrame 的一行。
     */

    val df=data.map(Tuple1.apply).toDF("features")

    //  调用Correlation包中的corr()函数来获取皮尔森相关性系数
    val Row(coeff1:Matrix) =Correlation.corr(df,"features").head
    println(coeff1)


    //  使用指定的斯皮尔曼相关性方法计算输入数据集的相关性
    val Row(coeff2:Matrix)=Correlation.corr(df,"features","spearman").head






    spark.close()
  }

}
